package funccode;

/*
 * Created on 2004-8-18
 *
 * 
 */

/**
 * @author pdv
 * 
 *         ���MODBUSӦ�ò��ַ��
 */
public class RegTblParser {
	private final String asciiStr;
	public static final int WORDLEN = 4;
	public static final int BYTELEN = 2;

	/**
	 * 
	 * @param asciiStr
	 *            ��ascii�ַ�ʽ���͵ĵ�ַ�� ����: ��ַ ���� 0000H 0x00FF 0001H 0xA001
	 * 
	 *            ���յ����ַ�Ϊ"00FFA001",��ַ��0��ʼ,��WORDΪ��λ����
	 */
	public RegTblParser(String asciiStr) {
		this.asciiStr = asciiStr;
	}

	/**
	 * ��ƫ�Ƶ�ַ���һ��unsigned byte
	 * 
	 * @param offset
	 *            ƫ�Ƶ�ַ
	 * @param isHigh
	 *            �Ƿ�Ϊ���ֽ�
	 * @throws RegTblParserException
	 */
	public int getUnsignedByte(int offset, boolean isHigh)
			throws RegTblParserException {
		int startadd;
		if (isHigh)
			startadd = offset * WORDLEN;
		else
			startadd = offset * WORDLEN + BYTELEN;
		return getUnsigned(startadd, BYTELEN);
	}

	/**
	 * ��ƫ�Ƶ�ַ���һ��signed byte
	 * 
	 * @param offset
	 *            ƫ�Ƶ�ַ
	 * @param isHigh
	 *            �Ƿ�Ϊ���ֽ�
	 * @throws RegTblParserException
	 */
	public int getSignedByte(int offset, boolean isHigh)
			throws RegTblParserException {
		int startadd;
		if (isHigh)
			startadd = offset * WORDLEN;
		else
			startadd = offset * WORDLEN + BYTELEN;
		return getSigned(startadd, BYTELEN);
	}

	/**
	 * ��ƫ�Ƶ�ַ���һ��unsigned word
	 * 
	 * @param offset
	 *            ƫ�Ƶ�ַ
	 * @throws RegTblParserException
	 */
	public int getUnsignedWord(int offset) throws RegTblParserException {
		return getUnsigned(offset * WORDLEN, WORDLEN);
	}

	/**
	 * ��ƫ�Ƶ�ַ���һ��signed word
	 * 
	 * @param offset
	 *            ƫ�Ƶ�ַ
	 * @throws RegTblParserException
	 */
	public int getSignedWord(int offset) throws RegTblParserException {
		return getSigned(offset * WORDLEN, WORDLEN);
	}

	/**
	 * �õ�ַ���Ƿ�������
	 * 
	 * @param offset
	 *            ƫ�Ƶ�ַ
	 * @return
	 */
	public boolean exists(int offset) {
		int endAddr = (offset + 1) * WORDLEN - 1;
		if (this.asciiStr.length() <= endAddr)
			return false;
		else
			return true;

	}

	private int getUnsigned(int startadd, int len) throws RegTblParserException {
		String tmpString = "";
		try {
			tmpString = asciiStr.substring(startadd, startadd + len);
			return Integer.parseInt(tmpString, 16);
		} catch (IndexOutOfBoundsException e) {
			throw new RegTblParserException("register table is too short");
		} catch (NumberFormatException e) {
			throw new RegTblParserException(tmpString + " format error");
		}
	}

	private int getSigned(int startadd, int len) throws RegTblParserException {
		String tmpString = "";
		try {
			tmpString = asciiStr.substring(startadd, startadd + len);
			char c = Character.toUpperCase(tmpString.charAt(0));
			char sign = '+';
			if (c == '8' || c == '9' || c == 'A' || c == 'B' || c == 'C'
					|| c == 'D' || c == 'E' || c == 'F') {
				sign = '-';
			}
			int n = Integer.parseInt(tmpString, 16);
			if (sign == '+')
				return n;
			else
				return n - (1 << 4 * len);
		} catch (IndexOutOfBoundsException e) {
			throw new RegTblParserException("register table is too short");
		} catch (NumberFormatException e) {
			throw new RegTblParserException(tmpString + " format error");
		}
	}

	/**
	 * ��ƫ�Ƶ�ַ���һ��word��bit string
	 * 
	 * @param offset
	 *            ƫ�Ƶ�ַ
	 * @throws RegTblParserException
	 */
	public String getWordBits(int offset) throws RegTblParserException {
		return getBits(offset * WORDLEN, WORDLEN);
	}

	/**
	 * ��ƫ�Ƶ�ַ���һ��byte��bit string
	 * 
	 * @param offset
	 *            ƫ�Ƶ�ַ
	 * @param isHigh
	 *            �Ƿ�Ϊ���ֽ�
	 * @throws RegTblParserException
	 */
	public String getByteBits(int offset, boolean isHigh)
			throws RegTblParserException {
		if (isHigh)
			return getBits(offset * WORDLEN, BYTELEN);
		else
			return getBits(offset * WORDLEN + BYTELEN, BYTELEN);
	}

	public String getCountBits(int start, int len) throws RegTblParserException {
		return this.getBits(start, len);
	}

	private String getBits(int startadd, int len) throws RegTblParserException {
		String tmpString = asciiStr.substring(startadd, startadd + len)
				.toUpperCase();
		StringBuffer buf = new StringBuffer();
		for (int i = 0; i < tmpString.length(); i++) {
			switch (tmpString.charAt(i)) {
			case '0':
				buf.append("0000");
				break;
			case '1':
				buf.append("0001");
				break;
			case '2':
				buf.append("0010");
				break;
			case '3':
				buf.append("0011");
				break;
			case '4':
				buf.append("0100");
				break;
			case '5':
				buf.append("0101");
				break;
			case '6':
				buf.append("0110");
				break;
			case '7':
				buf.append("0111");
				break;
			case '8':
				buf.append("1000");
				break;
			case '9':
				buf.append("1001");
				break;
			case 'A':
				buf.append("1010");
				break;
			case 'B':
				buf.append("1011");
				break;
			case 'C':
				buf.append("1100");
				break;
			case 'D':
				buf.append("1101");
				break;
			case 'E':
				buf.append("1110");
				break;
			case 'F':
				buf.append("1111");
				break;
			default:
				throw new RegTblParserException(tmpString.charAt(i)
						+ " can not be converted to binary string");
			}
		}
		return buf.toString();
	}

	private int hexTodec(char c) {
		switch (c) {
		case '0':
			return 0;
		case '1':
			return 1;
		case '2':
			return 2;
		case '3':
			return 3;
		case '4':
			return 4;
		case '5':
			return 5;
		case '6':
			return 6;
		case '7':
			return 7;
		case '8':
			return 8;
		case '9':
			return 9;
		case 'A':
		case 'a':
			return 10;
		case 'B':
		case 'b':
			return 11;
		case 'C':
		case 'c':
			return 12;
		case 'D':
		case 'd':
			return 13;
		case 'E':
		case 'e':
			return 14;
		case 'F':
		case 'f':
			return 15;
		default:
			return 0;
		}
	}

	public byte[] getBytes() {
		int len = asciiStr.length() / 2;
		byte[] res = new byte[len];
		for (int i = 0; i < len; i++) {
			res[i] = (byte) ((hexTodec(asciiStr.charAt(i * 2)) << 4) + hexTodec(asciiStr
					.charAt(i * 2 + 1)));
		}
		return res;
	}

	public byte[] getBytes(int offset, int len) throws RegTblParserException {
		byte[] res = new byte[len * 2];
		String s = asciiStr.substring(offset * WORDLEN, (offset + len)
				* WORDLEN);
		for (int i = 0; i < res.length; i++) {
			try {
				res[i] = (byte) ((hexTodec(s.charAt(i * 2)) << 4) + hexTodec(s
						.charAt(i * 2 + 1)));
			} catch (IndexOutOfBoundsException e) {
				throw new RegTblParserException("to short");
			}
		}
		return res;
	}

	public String getText(int offset, int len) throws RegTblParserException {
		byte[] b = getBytes(offset, len);
		int n = b.length;
		for (int i = b.length - 1; i >= 0; i--) {
			if (b[i] == 0) {
				n--;
			}
		}
		return new String(b, 0, n);
	}

	public RegTblParser subTable(int startadd, int len) {
		return new RegTblParser(asciiStr.substring(startadd * WORDLEN, startadd
				* WORDLEN + len * WORDLEN));
	}

	public String toString() {
		return this.asciiStr;
	}
}
